#include "DataSvrClient.h"
#include "DataSvrCommon.h"
#include "DataSvrClientProtoHelper.h"
#include "ProtoHelper.h"
#include "SocketHelper.h"


LoggerPtr DataSvrClient::_logger = Logger::getLogger("DataSvrClient");

int DataSvrClient::init(const char * svr_ip, const unsigned svr_port, const int conn_pool_size, const int conn_timeout, \
                                const int send_timeout, const int recv_timeout, const int max_response_size, \
				const int data_svr_id) {
        if (NULL == svr_ip || conn_pool_size < 1 || data_svr_id < 0) {
                LOG4CXX_ERROR(_logger, __FUNCTION__ << "init error, invalid args");
                return -1;
        }
        _svr_ip = svr_ip;
        _svr_port = svr_port;
        _conn_pool_size = conn_pool_size;
        _conn_timeout = conn_timeout;
        _send_timeout = send_timeout;
        _recv_timeout = recv_timeout;
        _max_response_size = max_response_size;
	_data_svr_id = data_svr_id;
        int ret = _pool.init(svr_ip, svr_port, conn_timeout, conn_pool_size);
        if (ret < 0) {
                LOG4CXX_ERROR(_logger, "conn pool init error, ret:" << ret << ", svr_ip:" << svr_ip << ", svr_port:" << \
                                svr_port << ", conn_timeout:" << conn_timeout << ", conn_pool_size:" << conn_pool_size);
                return -2;
        }
        LOG4CXX_INFO(_logger, "DataSvrClient init ok, svr_ip:" << svr_ip << ", svr_port:" << svr_port << ", conn_timeout:" << \
                        conn_timeout << ", conn_pool_size:" << ", send_timeout:" << send_timeout << ", recv_timeout:" << \
                        recv_timeout);
        return 1;
}

int DataSvrClient::create_file(int32_t dir_id, int64_t file_id) {
	if (dir_id < 0 || file_id < 0) {
		LOG4CXX_ERROR(_logger, __FUNCTION__ << ", invalid args");
		return DS_ERR_CLIENT_DETECTED_INVALID_ARGS;
	}
	SocketConnPtr cp;
        int ret = _pool.get(cp);
        if (ret < 0) {
                LOG4CXX_ERROR(_logger, __FUNCTION__ << ", could not get connection from pool, dir_id:" << dir_id << \
				", file_id:" << file_id << ", data_svr_id:" << _data_svr_id);
                return DS_ERR_CLIENT_TO_SVR_NETWORK_ERR;
        }
        string request = ds_build_request_create_file(dir_id, file_id);
        string response;
        ret = send_and_recv_cmd(cp, _send_timeout, _recv_timeout, request.c_str(), request.size(), _max_response_size, response);
        if (ret < 0) {
                LOG4CXX_ERROR(_logger, __FUNCTION__ << ", send and recv cmd error, ret:" << ret << ", dir_id:" << dir_id << \
				", file_id:" << file_id << ", data_svr_id:" << _data_svr_id);
                return DS_ERR_CLIENT_TO_SVR_NETWORK_ERR;
        }
        int result;
        ret = ds_parse_response_create_file(response.c_str(), result);
        if (ret < 0) return DS_ERR_INVALID_RESPONSE;
	if (result < 0) {
		LOG4CXX_ERROR(_logger, __FUNCTION__ << ", error, dir_id:" << dir_id << ", file_id:" << file_id << \
				", data_svr_id:" << _data_svr_id << ", response:" << response);
	}
	else {
		LOG4CXX_INFO(_logger, __FUNCTION__ << ", ok, dir_id:" << dir_id << ", file_id:" << file_id << ", data_svr_id:" << \
				_data_svr_id);
	}
        return result;
}

int DataSvrClient::delete_file(int32_t dir_id, int64_t file_id) {
	if (dir_id < 0 || file_id < 0) {
		LOG4CXX_ERROR(_logger, __FUNCTION__ << ", invalid args");
		return DS_ERR_CLIENT_DETECTED_INVALID_ARGS;
	}
	SocketConnPtr cp;
        int ret = _pool.get(cp);
        if (ret < 0) {
                LOG4CXX_ERROR(_logger, __FUNCTION__ << ", could not get connection from pool, dir_id:" << dir_id << \
				", file_id:" << file_id << ", data_svr_id:" << _data_svr_id);
                return DS_ERR_CLIENT_TO_SVR_NETWORK_ERR;
        }
        string request = ds_build_request_delete_file(dir_id, file_id);
        string response;
        ret = send_and_recv_cmd(cp, _send_timeout, _recv_timeout, request.c_str(), request.size(), _max_response_size, response);
        if (ret < 0) {
                LOG4CXX_ERROR(_logger, __FUNCTION__ << ", send and recv cmd error, ret:" << ret << ", dir_id:" << dir_id << \
				", file_id:" << file_id << ", data_svr_id:" << _data_svr_id);
                return DS_ERR_CLIENT_TO_SVR_NETWORK_ERR;
        }
        int result;
        ret = ds_parse_response_delete_file(response.c_str(), result);
        if (ret < 0) return DS_ERR_INVALID_RESPONSE;
	if (result < 0) {
		LOG4CXX_ERROR(_logger, __FUNCTION__ << ", error, dir_id:" << dir_id << ", file_id:" << file_id << ", data_svr_id:" << _data_svr_id << \
				", response:" << response);
	}
	else {
		LOG4CXX_INFO(_logger, __FUNCTION__ << ", ok, dir_id:" << dir_id << ", file_id:" << file_id << ", data_svr_id:" << _data_svr_id);
	}

        return result;
}


int DataSvrClient::read_file(int32_t dir_id, int64_t file_id, int64_t begin_pos, int32_t len, char * buf) {
	LOG4CXX_DEBUG(_logger, __FUNCTION__ << ", begin, dir_id:" << dir_id << ", file_id:" << file_id << ", begin_pos:" << \
				begin_pos << ", len:" << len << ", data_svr_id:" << _data_svr_id);
	if (dir_id < 0 || file_id < 0 || begin_pos < 0 || len < 0) {
		LOG4CXX_ERROR(_logger, __FUNCTION__ << ", invalid args");
		return DS_ERR_CLIENT_DETECTED_INVALID_ARGS;
	}
	if (0 == len) return OK_RESULT;
	SocketConnPtr cp;
        int ret = _pool.get(cp);
        if (ret < 0) {
                LOG4CXX_ERROR(_logger, __FUNCTION__ << ", could not get connection from pool, dir_id:" << dir_id << \
				", file_id:" << file_id << ", data_svr_id:" << _data_svr_id);
                return DS_ERR_CLIENT_TO_SVR_NETWORK_ERR;
        }
        string request = ds_build_request_read_file(dir_id, file_id, begin_pos, len);
        string response;
        ret = send_and_recv_cmd(cp, _send_timeout, _recv_timeout, request.c_str(), request.size(), _max_response_size, response);
        if (ret < 0) {
                LOG4CXX_ERROR(_logger, __FUNCTION__ << ", send and recv cmd error, ret:" << ret << ", dir_id:" << dir_id << \
				", file_id:" << file_id << ", data_svr_id:" << _data_svr_id);
                return DS_ERR_CLIENT_TO_SVR_NETWORK_ERR;
        }
        int result;
        ret = ds_parse_response_read_file(response.c_str(), result);
        if (ret < 0) return DS_ERR_INVALID_RESPONSE;
	if (OK_RESULT == result) {
		ret = recv_all(cp, buf, len, _recv_timeout);
		if (ret < 0) {
			LOG4CXX_ERROR(_logger, __FUNCTION__ << ", recv all error, dir_id:" << dir_id << ", file_id:" << file_id << ", data_svr_id:" << _data_svr_id << \
					", len:" << len << ", begin_pos:" << begin_pos << ", recv timeout:" << _recv_timeout);
			return DS_ERR_CLIENT_TO_SVR_NETWORK_ERR;
		}
		LOG4CXX_INFO(_logger, __FUNCTION__ << ", ok, dir_id:" << dir_id << ", file_id:" << file_id << ", data_svr_id:" << _data_svr_id);
        	return OK_RESULT;
	}
	LOG4CXX_ERROR(_logger, __FUNCTION__ << ", error, dir_id:" << dir_id << ", file_id:" << file_id << ", data_svr_id:" << _data_svr_id << \
			", response:" << response);
        return result;
}

int DataSvrClient::write_file(int32_t dir_id, int64_t file_id, int64_t begin_pos, int32_t len, const char * buf, int32_t mode) {

	LOG4CXX_DEBUG(_logger, __FUNCTION__ << ", begin, dir_id:" << dir_id << ", file_id:" << file_id << ", data_svr_id:" << \
				_data_svr_id);
	if (dir_id < 0 || file_id < 0) {
		LOG4CXX_ERROR(_logger, __FUNCTION__ << ", invalid args");
		return DS_ERR_CLIENT_DETECTED_INVALID_ARGS;
	}
	SocketConnPtr cp;
        int ret = _pool.get(cp);
        if (ret < 0) {
                LOG4CXX_ERROR(_logger, __FUNCTION__ << ", could not get connection from pool, dir_id:" << dir_id << \
				", file_id:" << file_id << ", data_svr_id:" << _data_svr_id);
                return DS_ERR_CLIENT_TO_SVR_NETWORK_ERR;
        }
        string request = ds_build_request_write_file(dir_id, file_id, begin_pos, len, mode);
        string response;
	LOG4CXX_DEBUG(_logger, __FUNCTION__ << ", begin send_cmd, dir_id:" << dir_id << ", file_id:" << file_id << \
				", data_svr_id:" << _data_svr_id);
	
	ret = send_cmd(cp, _send_timeout, request.c_str(), request.size());
        if (ret < 0) {
                LOG4CXX_ERROR(_logger, __FUNCTION__ << ", send cmd error, ret:" << ret << ", dir_id:" << dir_id << \
				", file_id:" << file_id << ", data_svr_id:" << _data_svr_id << ", len:" << len << ", begin_pos:" << begin_pos << \
				", recv timeout:" << _recv_timeout);
                return DS_ERR_CLIENT_TO_SVR_NETWORK_ERR;
        }
	LOG4CXX_DEBUG(_logger, __FUNCTION__ << ", begin send_all, dir_id:" << dir_id << ", file_id:" << file_id << \
				", data_svr_id:" << _data_svr_id);
	
	ret = send_all(cp, buf, len, _send_timeout);
        if (ret < 0) {
                LOG4CXX_ERROR(_logger, __FUNCTION__ << ", send all error, ret:" << ret << ", dir_id:" << dir_id << \
				", file_id:" << file_id << ", data_svr_id:" << _data_svr_id << ", len:" << len << ", begin_pos:" << begin_pos << \
				", recv timeout:" << _recv_timeout);
                return DS_ERR_CLIENT_TO_SVR_NETWORK_ERR;
        }
	LOG4CXX_DEBUG(_logger, __FUNCTION__ << ", begin recv_cmd, dir_id:" << dir_id << ", file_id:" << file_id << \
				", data_svr_id:" << _data_svr_id);
	
	ret = recv_cmd(cp, _recv_timeout, _max_response_size, response);
	if (ret < 0) {
                LOG4CXX_ERROR(_logger, __FUNCTION__ << ", recv cmd error, ret:" << ret << ", dir_id:" << dir_id << \
				", file_id:" << file_id << ", data_svr_id:" << _data_svr_id << ", len:" << len << ", begin_pos:" << begin_pos << \
				", recv timeout:" << _recv_timeout);
                return DS_ERR_CLIENT_TO_SVR_NETWORK_ERR;
        }
        int result;
        ret = ds_parse_response_write_file(response.c_str(), result);
        if (ret < 0) return DS_ERR_INVALID_RESPONSE;
	if (result < 0) {
		LOG4CXX_ERROR(_logger, __FUNCTION__ << ", error, dir_id:" << dir_id << ", file_id:" << file_id << ", data_svr_id:" << _data_svr_id << \
				", response:" << response);
	}
	else {
		LOG4CXX_INFO(_logger, __FUNCTION__ << ", ok, dir_id:" << dir_id << ", file_id:" << file_id << ", data_svr_id:" << _data_svr_id);
	}
        return result;
}

int DataSvrClient::get_file_control_info(int32_t dir_id, int64_t file_id, DS_FILE_CONTROL_INFO & info, int64_t & file_size) {
	if (dir_id < 0 || file_id < 0) {
		LOG4CXX_ERROR(_logger, __FUNCTION__ << ", invalid args");
		return DS_ERR_CLIENT_DETECTED_INVALID_ARGS;
	}
	SocketConnPtr cp;
        int ret = _pool.get(cp);
        if (ret < 0) {
                LOG4CXX_ERROR(_logger, __FUNCTION__ << ", could not get connection from pool, dir_id:" << dir_id << \
				", file_id:" << file_id << ", data_svr_id:" << _data_svr_id);
                return DS_ERR_CLIENT_TO_SVR_NETWORK_ERR;
        }
        string request = ds_build_request_get_file_control_info(dir_id, file_id);
        string response;
        ret = send_and_recv_cmd(cp, _send_timeout, _recv_timeout, request.c_str(), request.size(), _max_response_size, response);
        if (ret < 0) {
                LOG4CXX_ERROR(_logger, __FUNCTION__ << ", send and recv cmd error, ret:" << ret << ", dir_id:" << dir_id << \
				", file_id:" << file_id << ", data_svr_id:" << _data_svr_id);
                return DS_ERR_CLIENT_TO_SVR_NETWORK_ERR;
        }
        int result;
        ret = ds_parse_response_get_file_control_info(response.c_str(), result, info, file_size);
        if (ret < 0) return DS_ERR_INVALID_RESPONSE;
	if (result < 0) {
		LOG4CXX_ERROR(_logger, __FUNCTION__ << ", error, dir_id:" << dir_id << ", file_id:" << file_id << ", data_svr_id:" << _data_svr_id << \
				", response:" << response);
	}
	else {
		LOG4CXX_INFO(_logger, __FUNCTION__ << ", ok, dir_id:" << dir_id << ", file_id:" << file_id << ", data_svr_id:" << _data_svr_id);
	}
        return result;
}

int DataSvrClient::replicate(int32_t dir_id, int64_t file_id, int32_t src_ds_id, int64_t src_file_size, \
				vector<uint32_t> src_crcs) {
	if (dir_id < 0 || file_id < 0 || src_ds_id < 0 || src_file_size < 0) {
		LOG4CXX_ERROR(_logger, __FUNCTION__ << ", invalid args");
		return DS_ERR_CLIENT_DETECTED_INVALID_ARGS;
	}
	SocketConnPtr cp;
        int ret = _pool.get(cp);
        if (ret < 0) {
                LOG4CXX_ERROR(_logger, __FUNCTION__ << ", could not get connection from pool, dir_id:" << dir_id << \
				", file_id:" << file_id << ", data_svr_id:" << _data_svr_id);
                return DS_ERR_CLIENT_TO_SVR_NETWORK_ERR;
        }
        string request = ds_build_request_replicate(dir_id, file_id, src_ds_id, src_file_size, src_crcs);
        string response;
        ret = send_and_recv_cmd(cp, _send_timeout, _recv_timeout, request.c_str(), request.size(), _max_response_size, response);
        if (ret < 0) {
                LOG4CXX_ERROR(_logger, __FUNCTION__ << ", send and recv cmd error, ret:" << ret << ", dir_id:" << dir_id << \
				", file_id:" << file_id << ", data_svr_id:" << _data_svr_id);
                return DS_ERR_CLIENT_TO_SVR_NETWORK_ERR;
        }
        int result;
        ret = ds_parse_response_replicate(response.c_str(), result);
        if (ret < 0) return DS_ERR_INVALID_RESPONSE;
	if (result < 0) {
		LOG4CXX_ERROR(_logger, __FUNCTION__ << ", error, dir_id:" << dir_id << ", file_id:" << file_id << ", data_svr_id:" << _data_svr_id << \
				", response:" << response);
	}
	else {
		LOG4CXX_INFO(_logger, __FUNCTION__ << ", ok, dir_id:" << dir_id << ", file_id:" << file_id << ", data_svr_id:" << _data_svr_id);
	}
        return result;
}

int DataSvrClient::truncate(int32_t dir_id, int64_t file_id, int64_t size) {
	if (dir_id < 0 || file_id < 0 || size < 0) {
		LOG4CXX_ERROR(_logger, __FUNCTION__ << ", invalid args");
		return DS_ERR_CLIENT_DETECTED_INVALID_ARGS;
	}
	SocketConnPtr cp;
        int ret = _pool.get(cp);
        if (ret < 0) {
                LOG4CXX_ERROR(_logger, __FUNCTION__ << ", could not get connection from pool, dir_id:" << dir_id << \
				", file_id:" << file_id << ", data_svr_id:" << _data_svr_id);
                return DS_ERR_CLIENT_TO_SVR_NETWORK_ERR;
        }
        string request = ds_build_request_truncate(dir_id, file_id, size);
        string response;
        ret = send_and_recv_cmd(cp, _send_timeout, _recv_timeout, request.c_str(), request.size(), _max_response_size, response);
        if (ret < 0) {
                LOG4CXX_ERROR(_logger, __FUNCTION__ << ", send and recv cmd error, ret:" << ret << ", dir_id:" << dir_id << \
				", file_id:" << file_id << ", data_svr_id:" << _data_svr_id);
                return DS_ERR_CLIENT_TO_SVR_NETWORK_ERR;
        }
        int result;
        ret = ds_parse_response_truncate(response.c_str(), result);
        if (ret < 0) return DS_ERR_INVALID_RESPONSE;
	if (result < 0) {
		LOG4CXX_ERROR(_logger, __FUNCTION__ << ", error, dir_id:" << dir_id << ", file_id:" << file_id << ", data_svr_id:" << _data_svr_id << \
				", response:" << response);
	}
	else {
		LOG4CXX_INFO(_logger, __FUNCTION__ << ", ok, dir_id:" << dir_id << ", file_id:" << file_id << ", data_svr_id:" << _data_svr_id);
	}
        return result;
}
